/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.web.captcha.support;

import org.vacoor.nothing.web.captcha.ImageCaptcha;
import org.vacoor.nothing.web.captcha.ImageCaptchaDao;
import org.vacoor.nothing.web.captcha.ImageCaptchaEngine;
import org.vacoor.nothing.web.captcha.ImageCaptchaService;

import java.awt.image.BufferedImage;

/**
 * 以下两个都不错, 但是还是想再造个轮子
 * <p/>
 * jcaptcha: 很不错, 可惜 2.x 始终在 maven 中央仓库没有, 1.x 依赖中央仓库又没有
 * kaptcha: https://code.google.com/p/kaptcha/
 * TODO 对于并发高的情况, 1. 可以预先生成一批验证码存放 2. 重复利用
 *
 * @author vacoor
 */
public abstract class GeneralImageCaptchaService implements ImageCaptchaService {
    protected ImageCaptchaEngine imageCaptchaEngine;
    protected ImageCaptchaDao imageCaptchaDao;

    public GeneralImageCaptchaService() {
        imageCaptchaEngine = new SimpleGimpyEngine();
        imageCaptchaDao = new MemoryImageCaptchaDao();
    }

    @Override
    public BufferedImage getChallengeFor(String id) {
        ImageCaptcha captcha = imageCaptchaDao.read(id);

        // 不存在或者已经获取过值(脏读)
        if (null == captcha || captcha.hasGetChallengeBeenCalled()) {
            captcha = generateAndStoreCaptcha(id);
        }

        BufferedImage challenge = getChallengeClone(captcha);
        captcha.disposeChallenge();

        return challenge;
    }

    @Override
    public boolean validate(String id, String response) {
        return validate(id, response, true);
    }

    @Override
    public boolean validate(String id, String response, boolean remove) {
        ImageCaptcha captcha = imageCaptchaDao.read(id);

        // 给定验证码不存在
        if (null == captcha) {
            return false;
        }

        boolean valid = doValidate(captcha, response);

        if (remove) {
            imageCaptchaDao.delete(id);
        }
        return valid;
    }

    /**
     * 验证有效性
     *
     * @param captcha
     * @param response
     * @return
     */
    protected boolean doValidate(ImageCaptcha captcha, String response) {
        return captcha.validate(response);
    }

    /**
     * 生成并存储验证码
     *
     * @param id
     * @return
     */
    protected ImageCaptcha generateAndStoreCaptcha(String id) {
        ImageCaptcha captcha = imageCaptchaEngine.getCaptcha(id);
        imageCaptchaDao.store(id, captcha);

        return captcha;
    }

    /**
     * 获取验证的拷贝
     *
     * @return
     */
    protected BufferedImage getChallengeClone(ImageCaptcha captcha) {
        BufferedImage challenge = captcha.getChallenge();
        BufferedImage clone = new BufferedImage(challenge.getWidth(), challenge.getHeight(), challenge.getType());

        clone.getGraphics().drawImage(challenge, 0, 0, clone.getWidth(), clone.getHeight(), null);
        clone.getGraphics().dispose();

        return clone;
    }

    /* *******************
     *   getter / setter
     * ***************** */

    public ImageCaptchaEngine getImageCaptchaEngine() {
        return imageCaptchaEngine;
    }

    public void setImageCaptchaEngine(ImageCaptchaEngine imageCaptchaEngine) {
        this.imageCaptchaEngine = imageCaptchaEngine;
    }

    public ImageCaptchaDao getImageCaptchaDao() {
        return imageCaptchaDao;
    }

    public void setImageCaptchaDao(ImageCaptchaDao imageCaptchaDao) {
        this.imageCaptchaDao = imageCaptchaDao;
    }
}
